package com.zenith.common.util;

import com.zenith.common.constant.CommonConstant;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.Map;

/**
 * JWT工具类
 */
@Slf4j
public class JwtUtil {

    /**
     * 密钥
     */
    private static final SecretKey SECRET_KEY = Keys.hmacShaKeyFor("zenith-mind-pro-secret-key-32-byte-length".getBytes());

    /**
     * 过期时间（毫秒）
     */
    private static final long EXPIRATION = 86400000L; // 24小时

    /**
     * 生成JWT令牌（基础版本）
     *
     * @param userId   用户ID
     * @param username 用户名
     * @param role     角色
     * @return JWT令牌
     */
    public static String generateToken(Long userId, String username, String role) {
        Date now = new Date();
        Date expiration = new Date(now.getTime() + EXPIRATION);

        return Jwts.builder()
                .subject(username)
                .claim(CommonConstant.USER_ID, userId)
                .claim(CommonConstant.USERNAME, username)
                .claim(CommonConstant.USER_ROLE, role)
                .issuedAt(now)
                .expiration(expiration)
                .signWith(SECRET_KEY, SignatureAlgorithm.HS512)
                .compact();
    }

    /**
     * 生成JWT令牌（仅claims版本）
     *
     * @param claims 自定义声明
     * @return JWT令牌
     */
    public static String generateToken(Map<String, Object> claims) {
        Date now = new Date();
        Date expiration = new Date(now.getTime() + EXPIRATION);

        var builder = Jwts.builder()
                .issuedAt(now)
                .expiration(expiration)
                .signWith(SECRET_KEY, SignatureAlgorithm.HS512);

        // 添加自定义声明
        if (claims != null && !claims.isEmpty()) {
            claims.forEach(builder::claim);
            
            // 如果claims中包含username，则设置为subject
            if (claims.containsKey(CommonConstant.USERNAME)) {
                builder.subject(claims.get(CommonConstant.USERNAME).toString());
            }
        }

        return builder.compact();
    }

    /**
     * 生成JWT令牌（自定义claims版本）
     *
     * @param subject 令牌主题
     * @param claims  自定义声明
     * @return JWT令牌
     */
    public static String generateToken(String subject, Map<String, Object> claims) {
        Date now = new Date();
        Date expiration = new Date(now.getTime() + EXPIRATION);

        var builder = Jwts.builder()
                .subject(subject)
                .issuedAt(now)
                .expiration(expiration)
                .signWith(SECRET_KEY, SignatureAlgorithm.HS512);

        // 添加自定义声明
        if (claims != null && !claims.isEmpty()) {
            claims.forEach(builder::claim);
        }

        return builder.compact();
    }

    /**
     * 生成JWT令牌（完整自定义版本）
     *
     * @param subject    令牌主题
     * @param claims     自定义声明
     * @param expiration 过期时间（毫秒），如果为null则使用默认过期时间
     * @return JWT令牌
     */
    public static String generateToken(String subject, Map<String, Object> claims, Long expiration) {
        Date now = new Date();
        Date exp = expiration != null ? 
            new Date(now.getTime() + expiration) : 
            new Date(now.getTime() + EXPIRATION);

        var builder = Jwts.builder()
                .subject(subject)
                .issuedAt(now)
                .expiration(exp)
                .signWith(SECRET_KEY, SignatureAlgorithm.HS512);

        // 添加自定义声明
        if (claims != null && !claims.isEmpty()) {
            claims.forEach(builder::claim);
        }

        return builder.compact();
    }

    /**
     * 解析JWT令牌
     *
     * @param token JWT令牌
     * @return 声明
     */
    public static Claims parseToken(String token) {
        try {
            return Jwts.parser()
                    .verifyWith(SECRET_KEY)
                    .build()
                    .parseSignedClaims(token)
                    .getPayload();
        } catch (Exception e) {
            log.error("JWT令牌解析失败: {}", e.getMessage());
            return null;
        }
    }

    /**
     * 从令牌中获取用户ID
     *
     * @param token JWT令牌
     * @return 用户ID
     */
    public static Long getUserId(String token) {
        Claims claims = parseToken(token);
        return claims != null ? Long.valueOf(claims.get(CommonConstant.USER_ID).toString()) : null;
    }

    /**
     * 从令牌中获取用户名
     *
     * @param token JWT令牌
     * @return 用户名
     */
    public static String getUsername(String token) {
        Claims claims = parseToken(token);
        return claims != null ? claims.getSubject() : null;
    }

    /**
     * 从令牌中获取用户角色
     *
     * @param token JWT令牌
     * @return 用户角色
     */
    public static String getUserRole(String token) {
        Claims claims = parseToken(token);
        return claims != null ? claims.get(CommonConstant.USER_ROLE).toString() : null;
    }

    /**
     * 从令牌中获取指定的声明值
     *
     * @param token JWT令牌
     * @param key   声明的键
     * @return 声明的值
     */
    public static Object getClaim(String token, String key) {
        Claims claims = parseToken(token);
        return claims != null ? claims.get(key) : null;
    }

    /**
     * 验证令牌是否有效
     *
     * @param token JWT令牌
     * @return 是否有效
     */
    public static boolean validateToken(String token) {
        try {
            Claims claims = parseToken(token);
            return claims != null && !claims.getExpiration().before(new Date());
        } catch (Exception e) {
            return false;
        }
    }
}